using System;
using System.Collections.Generic;
using System.Text;
using Csla;
using Templates;
using NBearLite;
using Active.Core.DB;
using Csla.Data;

namespace Active.Core
{
    [Serializable()]
    public class Media : BusinessBase<Media>
    {
        #region Business Methods
        // TODO: add your own fields, properties and methods
        private int _id;
        public int Id
        {
            [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
            get
            {
                CanReadProperty(true);
                return _id;
            }
        }

        string _address = string.Empty;
        /// <summary>
        /// Gets or sets the address.
        /// </summary>
        /// <value>The address.</value>
        public string Address
        {
            [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
            get
            {
                CanReadProperty(true);
                return _address;
            }
            [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
            set
            {
                CanWriteProperty(true);
                if (_address!=value)
                {
                    _address = value;
                    PropertyHasChanged();
                }
            }
        }

        string _fax = string.Empty;
        /// <summary>
        /// Gets or sets the fax.
        /// </summary>
        /// <value>The fax.</value>
        public string Fax
        {
            [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
            get
            {
                CanReadProperty(true);
                return _fax;
            }
            [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
            set
            {
                CanWriteProperty(true);
                if (_fax != value)
                {
                    _fax = value;
                    PropertyHasChanged();
                }
            }
        }
        string _name = string.Empty;
        /// <summary>
        /// Gets or sets the name.
        /// </summary>
        /// <value>The name.</value>
        public string Name
        {
            [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
            get
            {
                CanReadProperty(true);
                return _name;
            }
            [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
            set
            {
                CanWriteProperty(true);
                if (_name != value)
                {
                    _name = value;
                    PropertyHasChanged();
                }
            }
        }

        int _regionId;
        /// <summary>
        /// Gets or sets the region id.
        /// </summary>
        /// <value>The region id.</value>
        public int RegionId
        {
            [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
            get
            {
                CanReadProperty(true);
                return _regionId;
            }
            [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
            set
            {
                CanWriteProperty(true);
                if (!_regionId.Equals(value))
                {
                    _regionId = value;
                    PropertyHasChanged();
                }
            }
        }

        string _tel = string.Empty;
        public string Tel
        {
            [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
            get
            {
                CanReadProperty(true);
                return _tel;
            }
            [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
            set
            {
                CanWriteProperty(true);
                if (_tel != value)
                {
                    _tel = value;
                    PropertyHasChanged();
                }
            }
        }

        decimal _advance;
        /// <summary>
        /// Gets or sets the advance.
        /// </summary>
        /// <value>The advance.</value>
        public decimal Advance
        {
            [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
            get
            {
                CanReadProperty(true);
                return _advance;
            }
            [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
            set
            {
                CanWriteProperty(true);
                if (!_advance.Equals(value))
                {
                    _advance = value;
                    PropertyHasChanged();
                }
            }
        }

        decimal _brokerage;
        /// <summary>
        /// Gets or sets the brokerage.
        /// </summary>
        /// <value>The brokerage.</value>
        public decimal Brokerage
        {
            [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
            get
            {
                CanReadProperty(true);
                return _brokerage;
            }
            [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
            set
            {
                CanWriteProperty(true);
                if (!_brokerage.Equals(value))
                {
                    _brokerage = value;
                    PropertyHasChanged();
                }
            }
        }

        string _channels = string.Empty;
        /// <summary>
        /// Gets or sets the channels.
        /// </summary>
        /// <value>The channels.</value>
        public string Channels
        {
            [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
            get
            {
                CanReadProperty(true);
                return _channels;
            }
            [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
            set
            {
                CanWriteProperty(true);
                if (_channels!=value)
                {
                    _channels = value;
                    PropertyHasChanged();
                }
            }
        }

        /// <summary>
        /// Gets the channels array.
        /// </summary>
        /// <value>The channels array.</value>
        public string[] ChannelsArray
        {
            get
            {
                if (string.IsNullOrEmpty(_channels))
                {
                    return new string[] { _name };
                }
                return _channels.Split(new string[] { Environment.NewLine }, 
                    StringSplitOptions.RemoveEmptyEntries);
            }
        }

        MediaType _category = MediaType.TV;
        /// <summary>
        /// Gets or sets the category.
        /// </summary>
        /// <value>The category.</value>
        public MediaType Category
        {
            [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
            get
            {
                CanReadProperty(true);
                return _category;
            }
            [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
            set
            {
                CanWriteProperty(true);
                if (!_category.Equals(value))
                {
                    _category = value;
                    PropertyHasChanged();
                }
            }
        }

        int _dealTimes;
        /// <summary>
        /// Gets or sets the deal times.
        /// </summary>
        /// <value>The deal times.</value>
        public int DealTimes
        {
            [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
            get
            {
                CanReadProperty(true);
                return _dealTimes;
            }
        }

        Contacts _contactList;
        /// <summary>
        /// Gets the contact list.
        /// </summary>
        /// <value>The contact list.</value>
        public Contacts ContactList
        {
            get
            {
                if (_contactList == null && _id > 0)
                {
                    _contactList = Contacts.GetMediaContacts(_id);
                }
                return _contactList;
            }
        }

        /// <summary>
        /// Override this method to return a unique identifying
        /// value for this object.
        /// </summary>
        /// <returns></returns>
        /// <remarks>
        /// If you can not provide a unique identifying value, it
        /// is best if you can generate such a unique value (even
        /// temporarily). If you can not do that, then return
        /// <see langword="Nothing"/> and then manually override the
        /// <see cref="Equals"/>, <see cref="GetHashCode"/> and
        /// <see cref="ToString"/> methods in your business object.
        /// </remarks>
        protected override object GetIdValue()
        {
            return _id;
        }

        /// <summary>
        /// Adds the advance.
        /// </summary>
        /// <param name="payValue">The pay value.</param>
        /// <param name="description">The description.</param>
        public void AddAdvance(decimal payValue, string description)
        {
            if (!(Utils.IsMediaEmployee
                || Utils.IsMediaManager
                || Utils.IsGeneralManager
                || Utils.IsFinanceEmployee))
                throw new System.Security.SecurityException(
                  "User not authorized to add advance");

            Check.Require(payValue > 0);
            Check.Require(!string.IsNullOrEmpty(description));

            AddAdvanceCommand result = DataPortal.Execute<AddAdvanceCommand>(
                new AddAdvanceCommand(_id, payValue, 
                Csla.ApplicationContext.User.Identity.Name, description));
            _advance = result.TotalAdvance;
        }

        /// <summary>
        /// Adds the brokerage.
        /// </summary>
        /// <param name="payValue">The pay value.</param>
        /// <param name="description">The description.</param>
        public void AddBrokerage(decimal payValue, string description)
        {
            if (!(Utils.IsMediaEmployee
                || Utils.IsMediaManager
                || Utils.IsGeneralManager
                || Utils.IsFinanceEmployee))
                throw new System.Security.SecurityException(
                  "User not authorized to add Brokerage");
            AddBrokerageCommand result = DataPortal.Execute<AddBrokerageCommand>(
                new AddBrokerageCommand(_id, payValue,
                Csla.ApplicationContext.User.Identity.Name, description));
            _brokerage = result.TotalBrokerage;
        }

        #endregion

        #region Validation Rules

        /// <summary>
        /// Override this method in your business class to
        /// be notified when you need to set up shared
        /// business rules.
        /// </summary>
        /// <remarks>
        /// This method is automatically called by CSLA .NET
        /// when your object should associate per-type
        /// validation rules with its properties.
        /// </remarks>
        protected override void AddBusinessRules()
        {
            // TODO: add validation rules
            //ValidationRules.AddRule(null, "");
            ValidationRules.AddRule(Csla.Validation.CommonRules.StringRequired, "Name");
        }

        #endregion

        #region Authorization Rules

        /// <summary>
        /// Override this method to add per-type
        /// authorization rules for your type's properties.
        /// </summary>
        /// <remarks>
        /// AddAuthorizationRules is automatically called by CSLA .NET
        /// when your object should associate per-type authorization roles
        /// with its properties.
        /// </remarks>
        protected override void AddAuthorizationRules()
        {
            // TODO: add authorization rules
            //AuthorizationRules.AllowWrite("", "");
        }

        /// <summary>
        /// Determines whether this instance [can add object].
        /// </summary>
        /// <returns>
        /// 	<c>true</c> if this instance [can add object]; otherwise, <c>false</c>.
        /// </returns>
        public static bool CanAddObject()
        {
            return Utils.IsMediaEmployee || Utils.IsMediaManager;
        }

        /// <summary>
        /// Determines whether this instance [can get object].
        /// </summary>
        /// <returns>
        /// 	<c>true</c> if this instance [can get object]; otherwise, <c>false</c>.
        /// </returns>
        public static bool CanGetObject()
        {
            return true;
        }

        /// <summary>
        /// Determines whether this instance [can edit object].
        /// </summary>
        /// <returns>
        /// 	<c>true</c> if this instance [can edit object]; otherwise, <c>false</c>.
        /// </returns>
        public static bool CanEditObject()
        {
            return Utils.IsMediaEmployee || Utils.IsMediaManager;
        }

        /// <summary>
        /// Determines whether this instance [can delete object].
        /// </summary>
        /// <returns>
        /// 	<c>true</c> if this instance [can delete object]; otherwise, <c>false</c>.
        /// </returns>
        public static bool CanDeleteObject()
        {
            return Utils.IsMediaManager;
        }

        #endregion

        #region Factory Methods

        /// <summary>
        /// News the media.
        /// </summary>
        /// <returns></returns>
        public static Media NewMedia()
        {
            if (!CanAddObject())
                throw new System.Security.SecurityException(
                  "User not authorized to add an Media");
            //return DataPortal.Create<Media>();
            return new Media();
        }

        /// <summary>
        /// Gets the Media.
        /// </summary>
        /// <param name="id">The id.</param>
        /// <returns></returns>
        public static Media GetMedia(int id)
        {
            if (!CanGetObject())
                throw new System.Security.SecurityException(
                  "User not authorized to view an Media");
            return DataPortal.Fetch<Media>(new Criteria(id));
        }

        public static Media GetMedia(string mediaName)
        {
            if (!CanGetObject())
                throw new System.Security.SecurityException(
                  "User not authorized to view an Media");
            return DataPortal.Fetch<Media>(new Criteria(mediaName));
        }

        /// <summary>
        /// Deletes the Media.
        /// </summary>
        /// <param name="id">The id.</param>
        public static void DeleteMedia(int id)
        {
            if (!CanDeleteObject())
                throw new System.Security.SecurityException(
                  "User not authorized to remove an Media");
            DataPortal.Delete(new Criteria(id));
        }

        public override Media Save()
        {
            if (IsDeleted && !CanDeleteObject())
                throw new System.Security.SecurityException(
                  "User not authorized to remove an Media");
            else if (IsNew && !CanAddObject())
                throw new System.Security.SecurityException(
                  "User not authorized to add an Media");
            else if (!CanEditObject())
                throw new System.Security.SecurityException(
                  "User not authorized to update an Media");
            return base.Save();
        }

        private Media()
        { /* Require use of factory methods */ }

        #endregion

        #region AddAdvanceCommand

        [Serializable()]
        private class AddAdvanceCommand : CommandBase
        {
            private int _mediaId;
            private decimal _payValue;
            private string _userName;
            private string _description;
            private decimal _totalAdvance;
            public AddAdvanceCommand(int mediaId, decimal payValue, string userName, string description)
            {
                _mediaId = mediaId;
                _payValue = payValue;
                _userName = userName;
                _description = description;
            }

            public decimal TotalAdvance
            {
                get { return _totalAdvance; }
            }

            [Transactional(TransactionalTypes.TransactionScope)]
            protected override void DataPortal_Execute()
            {
                DataService.DBService.Insert(Tables.Advances)
                    .AddColumn(Tables.Advances.Description, _description)
                    .AddColumn(Tables.Advances.OwnerId, _mediaId)
                    .AddColumn(Tables.Advances.PayValue, _payValue)
                    .AddColumn(Tables.Advances.SubmitDate, DateTime.Now)
                    .AddColumn(Tables.Advances.SubmitUser, _userName)
                    .Execute();
                _totalAdvance = (decimal)DataService.DBService.Select(Tables.Advances,
                    Tables.Advances.PayValue.Sum())
                    .Where(Tables.Advances.OwnerId == _mediaId).ToScalar();
                DataService.DBService.Update(Tables.Medias)
                    .AddColumn(Tables.Medias.Advance, _totalAdvance)
                    .Where(Tables.Medias.Id == _mediaId).Execute();
            }
        }

        #endregion
       
        #region AddBrokerageCommand

        [Serializable()]
        private class AddBrokerageCommand : CommandBase
        {
            private int _mediaId;
            private decimal _payValue;
            private string _userName;
            private string _description;
            private decimal _totalBrokerage;
            public AddBrokerageCommand(int mediaId, decimal payValue, string userName, string description)
            {
                _mediaId = mediaId;
                _payValue = payValue;
                _userName = userName;
                _description = description;
            }

            public decimal TotalBrokerage
            {
                get { return _totalBrokerage; }
            }

            [Transactional(TransactionalTypes.TransactionScope)]
            protected override void DataPortal_Execute()
            {
                DataService.DBService.Insert(Tables.Brokerages)
                    .AddColumn(Tables.Brokerages.Description, _description)
                    .AddColumn(Tables.Brokerages.OwnerId, _mediaId)
                    .AddColumn(Tables.Brokerages.PayValue, _payValue)
                    .AddColumn(Tables.Brokerages.SubmitDate, DateTime.Now)
                    .AddColumn(Tables.Brokerages.SubmitUser, _userName)
                    .Execute();
                _totalBrokerage = (decimal)DataService.DBService.Select(Tables.Brokerages,
                    Tables.Brokerages.PayValue.Sum())
                    .Where(Tables.Brokerages.OwnerId == _mediaId).ToScalar();
                DataService.DBService.Update(Tables.Medias)
                    .AddColumn(Tables.Medias.Brokerage, _totalBrokerage)
                    .Where(Tables.Medias.Id == _mediaId).Execute();
            }
        }

        #endregion

        #region Data Access

        [Serializable()]
        private class Criteria
        {
            private int _id;
            public int Id
            {
                get { return _id; }
            }
            public Criteria(int id)
            { _id = id; }

            private string _name;
            public string Name
            {
                get { return _name; }
            }
            public Criteria(string name)
            {
                _name = name;
            }
        }

        /// <summary>
        /// Override this method to load a new business object with default
        /// values from the database.
        /// </summary>
        /// <remarks>
        /// Normally you will overload this method to accept a strongly-typed
        /// criteria parameter, rather than overriding the method with a
        /// loosely-typed criteria parameter.
        /// </remarks>
        [RunLocal]
        protected override void DataPortal_Create()
        {
            //nothing to initialize
        }

        private void DataPortal_Fetch(Criteria criteria)
        {
            SelectSqlSection select =
                DataService.DBService.Select(Tables.Medias);
            NBearLite.WhereClip where = WhereClip.All;
            if (criteria.Id > 0)
            {
                where.And(Tables.Medias.Id == criteria.Id);
            }
            else
            {
                where.And(Tables.Medias.Name == criteria.Name);
            }
            select.Where(where);
            using (SafeDataReader dr = new SafeDataReader(select.ToDataReader()))
            {
                dr.Read();
                this._address = dr.GetString("Address");
                this._advance = dr.GetDecimal("Advance");
                this._brokerage = dr.GetDecimal("Brokerage");
                this._category = (MediaType)dr.GetInt32("Category");
                this._channels = dr.GetString("Channels");
                this._dealTimes = dr.GetInt32("DealTimes");
                this._fax = dr.GetString("Fax");
                this._name = dr.GetString("Name");
                this._regionId = dr.GetInt32("RegionId");
                this._tel = dr.GetString("Tel");
                this._id = dr.GetInt32("Id");
            }
        }

        [Transactional(TransactionalTypes.TransactionScope)]
        protected override void DataPortal_Insert()
        {
            InsertSqlSection insert =
                DataService.DBService.Insert(Tables.Medias)
                .AddColumn(Tables.Medias.Address, this._address)
                //.AddColumn(Tables.Medias.Advance, this._advance)
                //.AddColumn(Tables.Medias.Brokerage, this._brokerage)
                .AddColumn(Tables.Medias.Category, this._category)
                .AddColumn(Tables.Medias.Channels, this._channels)
                .AddColumn(Tables.Medias.DealTimes, this._dealTimes)
                .AddColumn(Tables.Medias.Fax, _fax)
                .AddColumn(Tables.Medias.Name, _name)
                .AddColumn(Tables.Medias.Tel, _tel)
                .AddColumn(Tables.Medias.RegionId, _regionId);
            _id = insert.ExecuteReturnAutoIncrementID(Tables.Medias.Id);
        }

        [Transactional(TransactionalTypes.TransactionScope)]
        protected override void DataPortal_Update()
        {
            DataService.DBService.Update(Tables.Medias)
                .AddColumn(Tables.Medias.Address, this._address)
                //.AddColumn(Tables.Medias.Advance, this._advance)
                //.AddColumn(Tables.Medias.Brokerage, this._brokerage)
                .AddColumn(Tables.Medias.Category, this._category)
                .AddColumn(Tables.Medias.Channels, this._channels)
                .AddColumn(Tables.Medias.DealTimes, this._dealTimes)
                .AddColumn(Tables.Medias.Fax, _fax)
                .AddColumn(Tables.Medias.Name, _name)
                .AddColumn(Tables.Medias.Tel, _tel)
                .AddColumn(Tables.Medias.RegionId, _regionId)
                .Where(Tables.Medias.Id == _id).Execute();
        }

        protected override void DataPortal_DeleteSelf()
        {
            DataPortal_Delete(new Criteria(_id));
        }

        [Transactional(TransactionalTypes.TransactionScope)]
        private void DataPortal_Delete(Criteria criteria)
        {
            DataService.DBService.Delete(Tables.Medias).Where(Tables.Medias.Id == criteria.Id).Execute();
        }

        #endregion

        public static bool CheckNameIsUsed(string name)
        {
            CheckNameCommand cmd = new CheckNameCommand(name);
            Csla.DataPortal.Execute<CheckNameCommand>(cmd);
            return cmd.Result;
        }

        #region CheckNameCommand

        [Serializable()]
        private class CheckNameCommand : CommandBase
        {
            #region Client-side Code

            string _name;
            bool _result = false;
            /// <summary>
            /// Gets a value indicating whether this <see cref="CheckNameCommand"/> is result.
            /// </summary>
            /// <value><c>true</c> if result; otherwise, <c>false</c>.</value>
            public bool Result
            {
                get { return _result; }
            }

            #endregion

            #region Factory Methods

            public CheckNameCommand(string name)
            {
                _name = name;
            }

            #endregion

            #region Server-side Code

            [Transactional(TransactionalTypes.TransactionScope)]
            protected override void DataPortal_Execute()
            {
                int c = (int)DB.DataService.DBService.Select(Tables.Medias, Tables.Medias.Id.Count())
                    .Where(Tables.Medias.Name == _name).ToScalar();
                _result = c != 0;
            }
            #endregion
        }

        #endregion
    }
}
